// Copyright (C) 2007-2021  CEA/DEN, EDF R&D, OPEN CASCADE
//
// Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
//
// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
//

#ifndef MED_SliceArray_HeaderFile
#define MED_SliceArray_HeaderFile

#ifdef WIN32 // for correct compiling of "valarray" in modules, which include this file
  #undef max
  #undef min
#endif

#include <valarray>
#include <stdexcept>

//#if defined(_DEBUG_)
#  define MED_TCSLICE_CHECK_RANGE
//#endif

namespace MED
{
  //---------------------------------------------------------------
  //! This class intends to provide a uniform way to handle multidimensional data (const version)
  /*!
    It just contains a pointer to real sequence and implement proper calculation of its indexes.
    This class deals with constant pointer to the sources data and provides const method to
    read them (data).
   */
  template<class TValueType>
  class TCSlice
  {
    const TValueType* myCValuePtr; //!< Reference to source multidimensional data
    size_t mySourceSize; //!< Size of the source multidimensional data
    std::slice mySlice; //!< Defines algorithm of index calculation

  protected:
    void
    check_id(size_t theId) const
    {
      long int anId = -1;
      if(theId < mySlice.size()){
        anId = mySlice.start() + theId*mySlice.stride();
        if(anId < (long int)mySourceSize)
          return;
      }
      throw std::out_of_range("TCSlice::check_id");
    }

    //! Calculate internal index to get proper element from the source multidimensional data
    size_t
    calculate_id(size_t theId) const
    {
      return mySlice.start() + theId*mySlice.stride();
    }

    size_t
    get_id(size_t theId) const
    {
#ifdef MED_TCSLICE_CHECK_RANGE
      check_id(theId);
#endif
      return calculate_id(theId);
    }

    size_t
    get_id_at(size_t theId) const
    {
      check_id(theId);
      return calculate_id(theId);
    }

  public:
    typedef TValueType value_type;

    //! Construct the class from bare pointer
    TCSlice(const value_type* theValuePtr,
            size_t theSourceSize,
            const std::slice& theSlice):
      myCValuePtr(theValuePtr),
      mySourceSize(theSourceSize),
      mySlice(theSlice)
    {}

    //! Construct the class from corresponding container
    TCSlice(const TVector<value_type>& theContainer,
            const std::slice& theSlice):
      myCValuePtr(&theContainer[0]),
      mySourceSize(theContainer.size()),
      mySlice(theSlice)
    {}

    //! Default constructor (dangerous)
    TCSlice():
      myCValuePtr(NULL)
    {}

    //! Get element by its number (const version)
    const value_type&
    operator[](size_t theId) const
    {
      return *(myCValuePtr + get_id(theId));
    }

    const value_type&
    at(size_t theId) const
    {
      return *(myCValuePtr + get_id_at(theId));
    }

    //! Get range of the order numbers
    size_t
    size() const
    {
      return mySlice.size();
    }
  };

  //---------------------------------------------------------------
  //! This class extends TCSlice functionality for non-constant case
  template<class TValueType>
  class TSlice: public TCSlice<TValueType>
  {
    TValueType* myValuePtr;

  public:
    typedef TValueType value_type;
    typedef TCSlice<TValueType> TSupperClass;

    //! Construct the class from bare pointer
    TSlice(value_type* theValuePtr,
           size_t theSourceSize,
           const std::slice& theSlice):
      TSupperClass(theValuePtr, theSourceSize, theSlice),
      myValuePtr(theValuePtr)
    {}

    //! Construct the class from corresponding container
    TSlice(TVector<value_type>& theContainer,
           const std::slice& theSlice):
      TSupperClass(theContainer, theSlice),
      myValuePtr(&theContainer[0])
    {}

    //! Default constructor (dangerous)
    TSlice():
      myValuePtr(NULL)
    {}

    //! Get element by its number
    value_type&
    operator[](size_t theId)
    {
      return *(myValuePtr + this->get_id(theId));
    }

    value_type&
    at(size_t theId)
    {
      return *(myValuePtr + this->get_id_at(theId));
    }
  };
}

#undef MED_TCSLICE_CHECK_RANGE

#endif // MED_SliceArray_HeaderFile
